package com.hzy.context;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.*;
import java.util.*;
import java.util.function.Function;

/**
 * PropertyResolver 类用于解析属性，支持从 Java 的 System.getenv() 和 Properties 对象中读取属性。
 * 它还支持解析和转换各种数据类型的属性值，包括基本类型和日期时间类型。
 */
public class PropertyResolver {

    Logger logger = LoggerFactory.getLogger(getClass());

    // 存储属性的 Map
    Map<String, String> properties = new HashMap<>();
    // 存储类型转换器的 Map
    Map<Class<?>, Function<String, Object>> converters = new HashMap<>();

    /**
     * 构造函数，初始化 PropertyResolver。
     *
     * @param props Properties 对象，用于初始化 PropertyResolver。
     */
    public PropertyResolver(Properties props) {
        // 将系统环境变量加入到 properties
        this.properties.putAll(System.getenv());
        // 将 props 中的属性加入到 properties
        Set<String> names = props.stringPropertyNames();
        for (String name : names) {
            this.properties.put(name, props.getProperty(name));
        }
        // 如果启用了调试日志，按顺序记录所有属性
        if (logger.isDebugEnabled()) {
            List<String> keys = new ArrayList<>(this.properties.keySet());
            Collections.sort(keys);
            for (String key : keys) {
                logger.debug("PropertyResolver: {} = {}", key, this.properties.get(key));
            }
        }
        // 注册各种类型转换器
        converters.put(String.class, s -> s);
        converters.put(boolean.class, Boolean::parseBoolean);
        converters.put(Boolean.class, Boolean::valueOf);

        converters.put(byte.class, Byte::parseByte);
        converters.put(Byte.class, Byte::valueOf);

        converters.put(short.class, Short::parseShort);
        converters.put(Short.class, Short::valueOf);

        converters.put(int.class, Integer::parseInt);
        converters.put(Integer.class, Integer::valueOf);

        converters.put(long.class, Long::parseLong);
        converters.put(Long.class, Long::valueOf);

        converters.put(float.class, Float::parseFloat);
        converters.put(Float.class, Float::valueOf);

        converters.put(double.class, Double::parseDouble);
        converters.put(Double.class, Double::valueOf);

        converters.put(LocalDate.class, LocalDate::parse);
        converters.put(LocalTime.class, LocalTime::parse);
        converters.put(LocalDateTime.class, LocalDateTime::parse);
        converters.put(ZonedDateTime.class, ZonedDateTime::parse);
        converters.put(Duration.class, Duration::parse);
        converters.put(ZoneId.class, ZoneId::of);
    }

    /**
     * 检查指定键的属性是否存在。
     *
     * @param key 属性键
     * @return 如果属性存在返回 true，否则返回 false
     */
    public boolean containsProperty(String key) {
        return this.properties.containsKey(key);
    }


    public String getProperty(String key) {
        PropertyExpr keyExpr = parsePropertyExpr(key);
        if (keyExpr != null) {
            if (keyExpr.defaultValue() != null) {
                return getProperty(keyExpr.key(), keyExpr.defaultValue());
            } else {
                return getRequiredProperty(keyExpr.key());
            }
        }
        String value = this.properties.get(key);
        if (value != null) {
            return parseValue(value);
        }
        return null;
    }

    /**
     * 获取属性值，如果属性不存在，则返回默认值。
     *
     * @param key          属性键
     * @param defaultValue 默认值
     * @return 属性值，如果不存在则返回默认值
     */
    public String getProperty(String key, String defaultValue) {
        String value = getProperty(key);
        return value == null ? parseValue(defaultValue) : value;
    }

    /**
     * 获取属性值并转换为指定类型，如果属性不存在，则返回 null。
     *
     * @param key        属性键
     * @param targetType 目标类型
     * @param <T>        泛型类型
     * @return 转换后的属性值，如果不存在则返回 null
     */

    public <T> T getProperty(String key, Class<T> targetType) {
        String value = getProperty(key);
        if (value == null) {
            return null;
        }
        return convert(targetType, value);
    }

    /**
     * 获取属性值并转换为指定类型，如果属性不存在，则返回默认值。
     *
     * @param key          属性键
     * @param targetType   目标类型
     * @param defaultValue 默认值
     * @param <T>          泛型类型
     * @return 转换后的属性值，如果不存在则返回默认值
     */
    public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
        String value = getProperty(key);
        if (value == null) {
            return defaultValue;
        }
        return convert(targetType, value);
    }

    /**
     * 获取必需的属性值，如果属性不存在，则抛出异常。
     *
     * @param key 属性键
     * @return 属性值
     * @throws NullPointerException 如果属性不存在
     */
    public String getRequiredProperty(String key) {
        String value = getProperty(key);
        return Objects.requireNonNull(value, "Property '" + key + "' not found.");
    }

    /**
     * 获取必需的属性值并转换为指定类型，如果属性不存在，则抛出异常。
     *
     * @param key        属性键
     * @param targetType 目标类型
     * @param <T>        泛型类型
     * @return 转换后的属性值
     * @throws NullPointerException 如果属性不存在
     */
    public <T> T getRequiredProperty(String key, Class<T> targetType) {
        T value = getProperty(key, targetType);
        return Objects.requireNonNull(value, "Property '" + key + "' not found.");
    }

    /**
     * 将字符串值转换为指定类型。
     *
     * @param clazz 目标类型
     * @param value 字符串值
     * @param <T>   泛型类型
     * @return 转换后的值
     * @throws IllegalArgumentException 如果不支持的类型
     */
    @SuppressWarnings("unchecked")
    <T> T convert(Class<?> clazz, String value) {
        Function<String, Object> fn = this.converters.get(clazz);
        if (fn == null) {
            throw new IllegalArgumentException("Unsupported value type: " + clazz.getName());
        }
        return (T) fn.apply(value);
    }

    /**
     * 解析属性值，支持取环境变量或系统属性。
     *
     * @param value 属性值
     * @return 解析后的值
     */
    String parseValue(String value) {
        PropertyExpr expr = parsePropertyExpr(value);
        if (expr == null) {
            return value;
        }
        if (expr.defaultValue() != null) {
            return getProperty(expr.key(), expr.defaultValue());
        } else {
            return getRequiredProperty(expr.key());
        }
    }

    /**
     * 解析属性表达式，支持带默认值的属性。
     *
     * @param key 属性键
     * @return PropertyExpr 对象，如果不符合表达式格式则返回 null
     */
    PropertyExpr parsePropertyExpr(String key) {
        if (key.startsWith("${") && key.endsWith("}")) {
            int n = key.indexOf(':');
            if (n == (-1)) {
                // 无默认值：${key}
                String k = notEmpty(key.substring(2, key.length() - 1));
                return new PropertyExpr(k, null);
            } else {
                // 有默认值：${key:default}
                String k = notEmpty(key.substring(2, n));
                return new PropertyExpr(k, key.substring(n + 1, key.length() - 1));
            }
        }
        return null;
    }

    /**
     * 确保键不为空，否则抛出异常。
     *
     * @param key 键值
     * @return 非空的键值
     * @throws IllegalArgumentException 如果键为空
     */
    String notEmpty(String key) {
        if (key.isEmpty()) {
            throw new IllegalArgumentException("Invalid key: " + key);
        }
        return key;
    }
}

/**
 * PropertyExpr 类用于表示属性表达式，包括属性键和默认值。
 */
record PropertyExpr(String key, String defaultValue) {
}
